package com.tpshion.util.tpsh.interceptor;

import com.tpshion.util.tpsh.support.ParameterWrapper;
import com.tpshion.util.tpsh.support.RequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class RequestLogInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(RequestLogInterceptor.class);

    private static final String START_TIME = "startTime";

    private static final String TRACE_ID = "traceId";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //放行options请求类型
        if(HttpMethod.OPTIONS.toString().equals(request.getMethod())){
            return true;
        }

        //如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        // 记录请求开始时间
        request.setAttribute(START_TIME, getTime());
        // 设置唯一请求id，以便于追踪请求链路
        request.setAttribute(TRACE_ID,getTraceId());
        // 打印请求方法和请求地址
        log.info("-------------------- [{}] path:{} start --------------------",request.getMethod(),request.getRequestURI());
        log.info("traceId:{}",request.getAttribute(TRACE_ID));
        log.info("path:[{}] {}",request.getMethod(),request.getRequestURI());
        log.info("contentType:{}",request.getContentType());
        log.info("queryString:{}",request.getQueryString());
        log.info("methodName:{}",method.getName());

        Parameter[] parameters = method.getParameters();
        List<ParameterWrapper> params = new ArrayList<ParameterWrapper>(parameters.length);
        for (Parameter parameter : parameters) {
            params.add(new ParameterWrapper(parameter.getParameterizedType().getTypeName(),parameter.getName()));
        }
        log.info("parameters:{}",params);

        if (isJson(request)) {
            // 获取json字符串
            String requestBody = new RequestWrapper(request).getBodyString();
            log.info("requestBody:{}", requestBody);
        }

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long costTime = getTime() - (long)request.getAttribute(START_TIME);
        log.info("-------------------- [{}] path:{} end cost:{}ms -------------\n",request.getMethod(),request.getRequestURI(),costTime);
    }

    /**
     * 获取时间戳
     * @return
     */
    private long getTime(){
        return LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
    }

    /**
     * 生成唯一的链路追踪id
     * @return
     */
    private String getTraceId(){
        return UUID.randomUUID().toString();
    }

    /**
     * 判断本次请求的数据类型是否为json
     * @param request
     * @return
     */
    private boolean isJson(HttpServletRequest request) {
        if (request.getContentType() != null) {
            return request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE) ||
                    request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE);
        }
        return false;
    }
}
